package com.gp.study.mybatis.session;

import java.io.File;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import com.gp.study.mybatis.annotation.Intercepts;
import com.gp.study.mybatis.annotation.Mapper;
import com.gp.study.mybatis.annotation.Select;
import com.gp.study.mybatis.bind.MapperProxyRegistry;
import com.gp.study.mybatis.executor.BaseExecutor;
import com.gp.study.mybatis.executor.CacheExecutor;
import com.gp.study.mybatis.executor.Executor;
import com.gp.study.mybatis.handler.StateMentHandler;
import com.gp.study.mybatis.interceptor.InterceptorChain;
import com.gp.study.mybatis.plugin.Interceptor;
import com.gp.study.mybatis.utils.FilenameUtils;

/**
 * 用户存储解析的各种配置
 * @author USER
 *
 */
public class Configuration {
	
	public static final ResourceBundle properties; // 全局配置
//	public static final ResourceBundle sqlMappings; // SQL映射关系配置，使用注解时不用重复配置
	private InterceptorChain interceptorChain = new InterceptorChain(); // 插件
	private MapperProxyRegistry mapperProxyRegistry = new MapperProxyRegistry();//维护接口和实例
	private List<Class<?>> mapperList = new ArrayList<>(); // 所有Mapper接口
    private List<String> classPaths = new ArrayList<>(); // 类所有文件
	/**
	 * 采用注解，所以在扫描的时候，解析注解，匹配接口和sql关系
	 * key: interfaceName.methodName
	 * value: sql
	 */
	public static final Map<String, MapperMethodMeta> mappedStatements = new HashMap<>(); // 维护接口方法与SQL关系

	static{
		properties = ResourceBundle.getBundle("config");
//		sqlMappings = ResourceBundle.getBundle("mybatis");
	}
	
	public Configuration() {
		//扫描 mapper  获取 mapper 接口需要扫描的package
		String mapperPath = properties.getString("mybatis.scan.mapper.path");
		scanFile(mapperPath);
		for(String className:classPaths){
			System.out.println(className);
			className=mapperPath+"."+FilenameUtils.getBaseName(className);
//			className = className.replace(mapperPath.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");
			Class<?> clz = null;
			try{
				clz = Class.forName(className);
				if(clz.isAnnotationPresent(Mapper.class)){
					mapperProxyRegistry.addMapper(clz);
					//继续扫描，接口方法
					Method[] methods = clz.getDeclaredMethods();
					for(Method method:methods){
						Select select = method.getAnnotation(Select.class);
						if(null != select){
							mappedStatements.putIfAbsent(className+"."+method.getName(),new MapperMethodMeta(select.sql(),method.getReturnType()));
						}
					}
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		//清空 ，重新扫描
		classPaths.clear();
		// 扫描 plugin  获取 interceptor 拦截器需要扫描的package
		String pluginPath = properties.getString("mybatis.scan.plugin.path");
		scanFile(pluginPath);
		for(String className:classPaths){
			System.out.println(className);
			className=pluginPath+"."+FilenameUtils.getBaseName(className);
			Class<?> clz = null;
			try{
				clz = Class.forName(className);
				if(clz.isAnnotationPresent(Intercepts.class)){
					Interceptor interceptor = (Interceptor) clz.newInstance();
					interceptorChain.addInterceptor(interceptor);
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
	private void scanFile(String path) {
		String basePath = this.getClass().getResource("/").getPath();
		path = path.replace(".",File.separator);
		File file = new File(basePath,path);
		doPath(file);
	}
	/**
     * 获取文件或文件夹下所有的类.class
     */
    private void doPath(File file) {
        // 文件夹，遍历
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f1 : files) {
                doPath(f1);
            }
        } else {
            // 文件，直接添加
            if (file.getName().endsWith(".class")) {
                classPaths.add(file.getPath());
            }
        }
    }
	/**
	 * 生成执行器
	 * 根据参数设置，是否开启缓存
	 * @return
	 */
	public Executor newExecutor() {
		Executor executor = new BaseExecutor(this);
		String cache = properties.getString("cache.enable");
		if(null!=cache && cache.equals("true") ){
			executor = new CacheExecutor(executor);
		}
		//拦截器处理
		interceptorChain.pluginAll(executor);
		return executor;
	}
	
	public <T> T getMapper(Class<?> type, DefaultSqlSession sqlSession){
		return (T) mapperProxyRegistry.getMapper(type, sqlSession);
	}

	/**
	 * 根据statemenid 获取 对应的 sql
	 * 肯定需要有个Map 来存储
	 * @param statementId
	 * @return
	 */
	public MapperMethodMeta getMapperStateMent(String statementId) {
		return mappedStatements.get(statementId);
	}
	public StateMentHandler newStateMentHandler() {
		return new StateMentHandler();
	}
	public boolean hasStatement(String statementId) {
		return mappedStatements.containsKey(statementId);
	}

}
